classdef dotsThePlayablesManager < dotsAllRemoteObjectManagers
    % @class dotsThePlayablesManager
    % @details
    % Manage objects in the playable* family
    
    properties
        % topsGroupedList of when playables were played.
        % Groups parallel the groups in managedObjects.  Mnemonics are
        % timestamps from when a playable was played.  Items are the
        % menmonics from managedObjects that identify the playable that was
        % playes.
        playTimes;
        
        % timestamp from when the last playable was played.
        lastPlayTime;
        
        % a fevalable cell array to invoke just before playing a playable.
        beforePlayFevalable;
    end
    
    properties (Access = protected)
        % a function to play or delegate to counterpart
        mayPlayFunction;
    end
    
    methods (Access=private)
        function self = dotsThePlayablesManager
            self.initialize;
        end
    end
    
    methods (Static=true)
        function pm = theObject
            persistent self
            if isempty(self) || ~isvalid(self)
                self = dotsThePlayablesManager;
            end
            pm = self;
        end
        
        function reset
            self = dotsThePlayablesManager.theObject;
            self.initialize;
        end
        
        function g = gui
            self = dotsThePlayablesManager.theObject;
            g = self.managedObjects.gui;
        end
    end
    
    methods
        function initialize(self)
            self.initialize@dotsAllRemoteObjectManagers;
            self.initializeLists({'playTimes'});
            
            self.shouldForwardToCounterpart = false;
            self.shouldCallToCounterpart = false;
            
            self.lastPlayTime = nan;
            
            % serverMode behavior should dominate
            if self.clientMode && ~self.serverMode
                self.mayPlayFunction = @requestPlayableWithUID;
            else
                self.mayPlayFunction = @playPlayableWithUID;
            end
            
            self.shouldForwardToCounterpart = true;
            self.shouldCallToCounterpart = true;
        end
        
        function step(self)
            if self.serverMode
                self.receiveTransactionsAsServer(true);
            end
            
            if self.clientMode
                self.receiveTransactionsAsClient(true);
            end
        end
        
        function when = mayPlayPlayable(self, playable)
            if ~isempty(self.beforePlayFevalable)
                feval(self.beforePlayFevalable{:});
            end
            when = feval(self.mayPlayFunction, self, playable.UID);
            self.lastPlayTime = when;
        end
        
        function when = playPlayableWithUID(self, playableUID)
            playable = self.managedObjects.getItemFromGroupWithMnemonic(self.defaultGroup, playableUID);
            when = feval(self.clockFunction);
            playable.mayPlayNow;
        end
        
        function when = requestPlayableWithUID(self, playableUID)
            when = [];
            self.finishAllTransactions;
            self.callToCounterpartWithReturn('lastPlayTime', ...
                'playPlayableWithUID', playableUID);
        end
    end
end